package com.example.demo.service;

import com.example.demo.dto.TorrentDetailResponse;
import com.example.demo.mapper.*;
import com.example.demo.model.*;
import com.example.demo.utils.BencodeUtil;
import com.example.demo.utils.TorrentUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.InetAddress;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Service
public class TorrentService {
    @Autowired
    private final TorrentMapper torrentMapper;
    private final Map<String, List<Map<String, Object>>> activePeers = new ConcurrentHashMap<>();
    @Autowired
    private PeerMapper peerMapper;
    @Autowired
    private TorrentSearchService torrentSearchService;

    @Autowired
    private UserCreditMapper userCreditMapper;

    @Autowired
    private CreditHistoryMapper creditHistoryMapper;

    @Autowired
    private UploadDownloadHistoryMapper uploadDownloadHistoryMapper;

    @Autowired
    private TorrentUsageMapper torrentUsageMapper;

    @Autowired
    private UserBehaviorMapper userBehaviorMapper;

    @Autowired
    private TorrentUsageMapper torrnentUsageMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private AppSettingMapper appSettingMapper;

    @Value("${torrent.storage.path}")
    private String storagePath;

    private static final String VIP_DISCOUNT_KEY = "vip";

    private static final String TORRENT_DEFAULT_VALUE = "torrent";


    public TorrentService(TorrentMapper torrentMapper) {
        this.torrentMapper = torrentMapper;
    }


    public String getInfoByTorrentId(String torrentId) {
        Torrent torrent = torrentMapper.findById(Long.parseLong(torrentId));
        if (torrent == null) {
            return null;
        }
        return torrent.getInfoHash();
    }

    public Torrent getTorrentByHash(String infoHash) {
        return torrentMapper.findByInfoHash(infoHash);
    }

    // 增强统计更新逻辑
    public void updatePeerStats(Torrent torrent, String event) {
        switch (event.toLowerCase()) {
            case "started":
                torrent.setLeechers(torrent.getLeechers() + 1);
                break;
            case "stopped":
                if (torrent.getSeeders() > 0) {
                    torrent.setSeeders(torrent.getSeeders() - 1);
                }
                break;
            case "completed":
                if (torrent.getLeechers() > 0) {
                    torrent.setLeechers(torrent.getLeechers() - 1);
                }
                torrent.setSeeders(torrent.getSeeders() + 1);
                break;
        }
        torrentMapper.updatePeerStats(torrent);
    }

    // 获取Peer列表（简化实现）
    public List<Map<String, Object>> getPeerList(String infoHash) {
        return activePeers.getOrDefault(infoHash, Collections.emptyList());
    }

    public Torrent uploadTorrent(File file,MultipartFile multipartFile, Torrent torrent) throws IOException {
        // 1. 计算 InfoHash
        if (!file.exists()) {
            throw new FileNotFoundException("上传文件已丢失");
        }
        String infoHash = TorrentUtil.getInfoHash(file);

        // 2. 保存种子文件到存储路径
        Path dir = Paths.get(storagePath);
        if (!Files.exists(dir)) {
            try {
                Files.createDirectories(dir);
                System.out.println("目录已创建");
            } catch (IOException e) {
                throw new IOException("无法创建存储目录: " + dir, e);
            }
        }

        // 使用File的标准方法获取文件名
        String fileName = multipartFile.getOriginalFilename();
        Path filePath = dir.resolve(Objects.requireNonNull(multipartFile.getOriginalFilename()));
        Files.write(filePath, multipartFile.getBytes());

//        // 使用NIO方式复制文件
//        Files.copy(file.toPath(), filePath, StandardCopyOption.REPLACE_EXISTING);

        // 3. 创建 Torrent 记录
        setupTorrentProperties(torrent, fileName, file.length(), infoHash);

        // 4. 插入数据库
        torrentMapper.insertTorrent(torrent);
        // 异步更新ES索引（搜索功能）
        CompletableFuture.runAsync(() -> {
            torrentSearchService.indexTorrent(torrent);
        });

        // 5. 更新用户积分
        updateUserCredit(getCurrentUserId(), 100, "TORRENT_UPLOAD");

        // 6. 记录上传历史
        UploadDownloadHistory history = new UploadDownloadHistory();
        history.setUserId(getCurrentUserId());
        history.setTorrentId(torrent.getId());
        history.setActionType("UPLOAD");
        history.setCreatedAt(LocalDateTime.now());
        uploadDownloadHistoryMapper.insertHistory(history);

        return torrent;
    }

    public String saveCoverImage(MultipartFile coverImage) throws IOException {
        // 定义图片存储路径
        String uploadDir = "uploads/covers/";
        File uploadDirFile = new File(uploadDir);
        if (!uploadDirFile.exists()) {
            uploadDirFile.mkdirs();
        }

        // 生成唯一的图片文件名
        String originalFilename = coverImage.getOriginalFilename();
        String fileExtension = originalFilename.substring(originalFilename.lastIndexOf("."));
        String uniqueFilename = UUID.randomUUID().toString() + fileExtension;

        // 保存图片到指定路径
        Path coverPath = Paths.get(uploadDir, uniqueFilename);
        Files.copy(coverImage.getInputStream(), coverPath, StandardCopyOption.REPLACE_EXISTING);

        // 返回图片的访问URL
        return uniqueFilename; // 返回相对于服务器的路径
    }
    public String convertImageToBase64(String imageUrl) {
        try {
            // 获取图片文件路径
            Path imagePath = Paths.get("uploads/covers/", imageUrl);
            if (!Files.exists(imagePath)) {
                return null; // 图片不存在
            }

            // 读取图片文件并转换为Base64
            byte[] imageBytes = Files.readAllBytes(imagePath);
            String base64Encoded = Base64.getEncoder().encodeToString(imageBytes);

            // 返回Base64格式的数据
            return "data:image/png;base64," + base64Encoded; // 假设图片是PNG格式
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }



    //下载种子文件
    @Transactional
    public void downloadTorrent(long torrentId) throws IOException {
        // 1. 获取种子信息
        Torrent torrent = torrentMapper.findById(torrentId);
        if (torrent == null) {
            throw new IllegalArgumentException("种子不存在");
        }

        // 2. 获取当前用户
        Long userId = getCurrentUserId();

        // 3.判断是否处于限免，非限免则进行正常扣分逻辑
        if (isValidPromotion(torrent)) {
            // 限免下载，跳过扣积分
            log.info("用户{}通过促销下载种子{}", userId, torrentId);
        } else {
            // 正常扣积分逻辑
            processNormalDownload(userId, torrent);
        }

        // 4. 记录积分变更历史
        CreditHistory creditHistory = new CreditHistory();
        creditHistory.setUserId(userId);
        creditHistory.setAmount(-50);
        creditHistory.setReason("TORRENT_DOWNLOAD");
        creditHistory.setCreatedAt(LocalDateTime.now());
        creditHistoryMapper.insertCreditHistory(creditHistory);

        // 新增：记录用户下载行为（用于推荐系统）
        recordUserBehavior(userId, torrentId, UserBehavior.BehaviorType.DOWNLOAD);

        // 6. 记录下载量
        torrent.setLeechers(torrent.getLeechers() + 1);
        torrentMapper.updatePeerStats(torrent);

        // 7. 记录下载次数
        torrnentUsageMapper.initStats(torrent.getId()); // 确保记录存在
        torrnentUsageMapper.incrementDownloadCount(torrent.getId(), 1);

    }
    // 在 TorrentService.java 中添加以下方法

    public void recordUserBehavior(Long userId, Long torrentId, UserBehavior.BehaviorType behaviorType) {
        UserBehavior behavior = new UserBehavior();

        // 设置用户
        User user = new User();
        user.setId(userId);
        behavior.setUser(user);

        // 设置种子
        Torrent torrent = new Torrent();
        torrent.setId(torrentId);
        behavior.setTorrent(torrent);

        behavior.setBehaviorType(behaviorType);
        behavior.setCreatedAt(LocalDateTime.now());

        // 保存行为记录
        userBehaviorMapper.insert(behavior);
    }

    private Long getCurrentUserId() {
        User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        return user.getId();
    }

    // 假设在某个方法中处理种子文件的元数据
        public void modifyTorrentTracker(Torrent torrent) throws IOException {
        // 获取种子文件路径
        Path torrentFilePath = Paths.get(storagePath).resolve(torrent.getFileName());
        User member = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        // 读取种子文件内容
        byte[] torrentBytes = Files.readAllBytes(torrentFilePath);
        // 将种子文件字节数组解析为 Bencoded 格式（具体解析方式取决于使用的库）
        // 这里假设有一个方法可以解析和修改种子文件的元数据
        Map<String, Object> torrentMetadata = BencodeUtil.decodeISO(torrentBytes);

        // 修改 tracker URL，添加 test 字段
        // 假设 tracker URL 存储在一个名为 "announce" 的键中
        if (torrentMetadata.containsKey("announce")) {
            String originalTrackerUrl = (String) torrentMetadata.get("announce");
            if (originalTrackerUrl.contains("?passkey")) {
                // 如果包含，则截取到 ?passkey 之前的部分
                originalTrackerUrl = originalTrackerUrl.substring(0, originalTrackerUrl.indexOf("?"));
            }

            String newTrackerUrl = originalTrackerUrl + String.format("?passkey=%s", member.getId());
            torrentMetadata.put("announce", newTrackerUrl);
        }
        // 将修改后的元数据重新编码为 Bencode 格式，并保存到文件
        byte[] modifiedTorrentBytes = BencodeUtil.encodeISOBytes(torrentMetadata);
        Files.write(torrentFilePath, modifiedTorrentBytes);
    }


    // 获取种子文件
    public Resource getTorrentFile(Torrent torrent) throws IOException {
        System.out.println("Torrent file name: " + torrent.getFileName());
        modifyTorrentTracker(torrent);
        Path filePath = Paths.get(storagePath).resolve(torrent.getFileName());
        Resource resource = new UrlResource(filePath.toUri());
        if (resource.exists() && resource.isReadable()) {
            return resource;
        } else {
            throw new IOException("File not found: " + torrent.getFileName());
        }
    }

    // 获取所有种子
    public List<Torrent> getAllTorrents() {
        List<Torrent> torrents = torrentMapper.findAll();

        // 为每个 Torrent 设置附加数据
        torrents.forEach(torrent -> {
            // 格式化数据
            torrent.formatData();

            // 设置下载次数（从 TorrentUsage 获取）
            TorrentUsage usage = torrentUsageMapper.findByTorrentId(torrent.getId());
            torrent.setDownloads(usage != null ? usage.getDownloadCount() : 0);
        });

        return torrents;
    }

    public Torrent viewTorrentById(Long torrentId) {
        User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        Long userId = user.getId();
        Torrent torrent = torrentMapper.findById(torrentId);
        if (torrent == null) {
            throw new IllegalArgumentException("种子不存在");
        }
        torrent.formatData();

        // 设置下载次数（从 TorrentUsage 获取）
        TorrentUsage usage = torrentUsageMapper.findByTorrentId(torrent.getId());
        torrent.setDownloads(usage != null ? usage.getDownloadCount() : 0);
        recordUserBehavior(userId, torrentId, UserBehavior.BehaviorType.VIEW);

        return torrent;
    }

    // 增强Peer注册逻辑 核心 *************************
    public void registerPeer(String infoHash, String peerId, int port, String ip, long left,long uploaded, long downloaded, String passkey) {
        Torrent torrent = torrentMapper.findByInfoHash(infoHash);
        if (torrent == null) return;

        // 查询或创建Peer
        Peer peer = peerMapper.findByPeerIdAndTorrentId(peerId, torrent.getId());
        if (peer == null) {
            peer = new Peer();
            peer.setPeerId(peerId);
            peer.setTorrent(torrent);
            peer.setIp(ip);
            peer.setPort(port);
            peer.setLastUpdated(new Date());
            peer.setUploaded(uploaded);
            peer.setDownloaded(downloaded);
            peer.setRemaining(torrent.getFileSize());
            peer.setSeeder(false); // 初始为Leecher
            peer.setUserId(Long.valueOf(passkey));
            peerMapper.insertPeer(peer);
        } else {
            peer.setRemaining(left);
            peer.setIp(ip);
            peer.setPort(port);
            peer.setLastUpdated(new Date());
            peer.setUploaded(peer.getUploaded() + uploaded);
            peer.setDownloaded(peer.getDownloaded() + downloaded);
            peerMapper.updatePeer(peer);
        }

        // 更新用户数据
        updateUserStats((long) Integer.parseInt(passkey), uploaded, downloaded);

        // 更新内存中的活跃Peer列表（可选，根据性能需求）
        Map<String, Object> peerMap = new HashMap<>();
        peerMap.put("peer_id", peerId);
        peerMap.put("ip", ip);
        peerMap.put("port", port);
        peerMap.put("last_seen", System.currentTimeMillis());
        activePeers.compute(infoHash, (k, v) -> {
            List<Map<String, Object>> peers = (v == null) ? new ArrayList<>() : v;
            peers.removeIf(p -> peerId.equals(p.get("peer_id"))); // 去重
            peers.add(peerMap);
            return peers;
        });
    }

    // 在TorrentService中添加，获取peer ***********************
    public String getCompactPeerList(String infoHash) {
        List<Map<String, Object>> peers = activePeers.getOrDefault(infoHash, Collections.emptyList());
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        System.out.println("Compact Peer" +peers);
        peers.forEach(peer -> {
            try {
                // 使用紧凑格式：4字节IP + 2字节端口
                byte[] ipBytes = InetAddress.getByName((String)peer.get("ip")).getAddress();
                int port = (Integer)peer.get("port");

                bos.write(ipBytes);
                bos.write((port >> 8) & 0xFF);
                bos.write(port & 0xFF);
            } catch (Exception e) {
                // 记录错误日志
                System.err.println("处理Peer IP/Port失败: " + e.getMessage());
            }
        });

        // 将字节数组转换为字符串
        try {
            return new String(bos.toByteArray(), Charset.forName("ISO-8859-1"));
        } catch (Exception e) {
            System.err.println("将字节数组转换为字符串时出错: " + e.getMessage());
            return "";
        }

    }

    public void deleteTorrent(Long id) {
        torrentMapper.deleteById(id);
        // 同步删除ES索引
        torrentSearchService.deleteTorrent(id);
    }

    // 修改积分操作方法
    private void updateUserCredit(Long userId, int amount, String reason) {
        UserCredit credit = userCreditMapper.findByUserId(userId);
        if (credit == null) {
            credit = new UserCredit();
            credit.setUserId(userId);
            credit.setBalance(0);
            userCreditMapper.insertUserCredit(credit);
        }

        int newBalance = credit.getBalance() + amount;
        userCreditMapper.updateBalance(userId, newBalance);

        CreditHistory history = new CreditHistory();
        history.setUserId(userId);
        history.setAmount(amount);
        history.setReason(reason);
        history.setCreatedAt(LocalDateTime.now());
        creditHistoryMapper.insertCreditHistory(history);
    }

    public void incrementUploadCount(Long torrentId) {
        torrentUsageMapper.initStats(torrentId); // 确保记录存在
        torrentUsageMapper.incrementUploadCount(torrentId, 1);
    }

    public void incrementDownloadCount(Long torrentId) {
        torrentUsageMapper.initStats(torrentId); // 确保记录存在
        torrentUsageMapper.incrementDownloadCount(torrentId, 1);
    }

    public Map<String, Long> getUsageStats(Long torrentId) {
        TorrentUsage usage = torrentUsageMapper.findByTorrentId(torrentId);
        return Map.of(
                "uploadCount", usage != null ? usage.getUploadCount() : 0L,
                "downloadCount", usage != null ? usage.getDownloadCount() : 0L
        );
    }

    public Torrent getTorrentById(Long torrentId) {
        return torrentMapper.findById(torrentId);
    }

    private void setupTorrentProperties(Torrent torrent, String fileName, long fileSize, String infoHash) {
        torrent.setFileName(fileName);
        torrent.setFileSize(fileSize);
        torrent.setInfoHash(infoHash);
        torrent.setUploaderId(getCurrentUserId());
        torrent.setCreateTime(LocalDateTime.now());
        torrent.setSeeders(0);
        torrent.setLeechers(0);

        // 设置默认值
        if (torrent.getCost() == null || torrent.getCost().isEmpty()) {
            torrent.setCost("50"); // 默认下载需要50积分
        }
        if (torrent.getScore() == 0) {
            torrent.setScore(50); // 默认种子积分
        }
    }
    public void updateUserStats(Long userId, long uploadedDelta, long downloadedDelta) {
        // 获取用户信息
        User user = userMapper.findById(userId);
        if (user == null) {
            return; // 用户不存在，直接返回
        }

        // 更新上传量和下载量
        String newUpload = String.valueOf(Long.parseLong(user.getUpload()) + uploadedDelta);
        String newDownload = String.valueOf(Long.parseLong(user.getDownload()) + downloadedDelta);

        // 更新用户记录
        userMapper.updateUploadDownload(userId, newUpload, newDownload);

        // 更新分享率
        double shareRating = Integer.parseInt(newDownload) != 0 ? (Double.parseDouble(newUpload) /+ Double.parseDouble(newDownload)) : Double.parseDouble(newDownload);
        userMapper.updateShareRating(userId, shareRating);
    }

    public TorrentDetailResponse getTorrentDetail(Long torrentId) {
        // 获取种子信息
        Torrent torrent = torrentMapper.findById(torrentId);
        if (torrent == null) {
            throw new IllegalArgumentException("Torrent not found");
        }

        // 获取封面图片的Base64编码
        String coverImageBase64 = null;
        if (torrent.getCoverImage() != null) {
            // 将图片URL转换为Base64
            coverImageBase64 = convertImageToBase64(torrent.getCoverImage());
        }

        // 获取做种者列表（假设Peer表中isSeeder=true表示做种者）
        List<Peer> seeders = peerMapper.findSeedersByTorrentIdWithUsername(torrentId);

        // 获取下载者列表
        List<UploadDownloadHistory> downloaders = uploadDownloadHistoryMapper.findDownloadsByTorrentIdWithUsername(torrentId);

        // 构建并返回 TorrentDetailResponse
        return new TorrentDetailResponse(torrent, coverImageBase64, seeders, downloaders);
    }


    private boolean isValidPromotion(Torrent torrent) {
        return torrent.isPromotionFree() &&
                LocalDateTime.now().isAfter(torrent.getPromotionStartTime()) &&
                LocalDateTime.now().isBefore(torrent.getPromotionEndTime());
    }

    public double getTorrentDefaultCost(){
        Optional<AppSetting> setting = appSettingMapper.findByConfigKey(TORRENT_DEFAULT_VALUE);
        return setting.map(AppSetting::getConfigValue).orElse(50.0);
    }

    private double getVipDiscountRate() {
        Optional<AppSetting> setting = appSettingMapper.findByConfigKey(VIP_DISCOUNT_KEY);
        return setting.map(AppSetting::getConfigValue).orElse(1.0); // 默认无折扣
    }

    private int calculateFinalPrice(Torrent torrent, boolean isVip) {
        if (isValidPromotion(torrent)) {
            return 0; // 限免时价格为0
        }

        int basePrice = torrent.getScore();
        if (isVip) {
            double discountRate = getVipDiscountRate();
            log.info(String.valueOf(discountRate));
            return (int) Math.round(basePrice * discountRate);
        }
        return basePrice;
    }

    private void recordCreditHistory(Long userId, int amount, String reason) {
        CreditHistory history = new CreditHistory();
        history.setUserId(userId);
        history.setAmount(amount);
        history.setReason(reason);
        history.setCreatedAt(LocalDateTime.now());
        creditHistoryMapper.insertCreditHistory(history);
    }

    private void processNormalDownload(Long userId, Torrent torrent) {
        // 获取用户信息 (从数据库重新加载以确保最新)
        User freshUser = userMapper.findById(userId);
        if (freshUser == null) {
            throw new UsernameNotFoundException("User not found with id: " + userId);
        }

        log.info("User isVip value: {}", freshUser.getIsVip()); // 使用 freshUser
        // 计算最终价格
        int finalPrice = calculateFinalPrice(torrent, freshUser.getIsVip()); // 使用 freshUser
        log.info("User isVip value for calculation: {}", freshUser.getIsVip());


        // 原有扣除积分逻辑...
        UserCredit credit = userCreditMapper.findByUserId(userId);
        if (credit == null || credit.getBalance() < finalPrice) {
            throw new IllegalStateException("积分不足，无法下载");
        }

        int updated = userCreditMapper.updateBalanceWithLock(
                userId,
                credit.getBalance(),
                credit.getBalance() - finalPrice
        );

        if (updated == 0) {
            throw new ConcurrentModificationException("积分变更冲突，请重试");
        }

        recordCreditHistory(userId, -finalPrice,
                freshUser.getIsVip() ? "VIP_TORRENT_DOWNLOAD" : "TORRENT_DOWNLOAD"); // 使用 freshUser
    }

}